package com.sxt.jt808.server;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.util.ResourceLeakDetector;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author: 罗林
 * @Date: 2019-12-15
 * @Description: Netty服务器端
 * @Version: 1.0
 */
@Slf4j
@Component
public class NettyTcpServer {

	// 端口号
	@Value("${netty.port}")
	private Integer port;

	//
	private EventLoopGroup bossGroup = null;
	//
	private EventLoopGroup workerGroup = null;

	@Autowired
	private JT808ChannelInitializer jt808ChannelInitializer;

	/**
	 * 启动Server
	 *
	 * @throws InterruptedException
	 */
	@PostConstruct
	public void start() throws InterruptedException {
		/** 针对linux优化 */
		String osName = System.getProperty("os.name");
		/** 配置服务端的NIO线程组 */
		if (osName.equalsIgnoreCase("Linux")) {
			/** 负责服务端接收客户端的连接 */
			this.bossGroup = new EpollEventLoopGroup();
			/** 负责进行SocketChannel的网络读写 */
			this.workerGroup = new EpollEventLoopGroup();
		} else {
			/** 负责服务端接收客户端的连接 */
			this.bossGroup = new NioEventLoopGroup();
			/** 负责进行SocketChannel的网络读写 */
			this.workerGroup = new NioEventLoopGroup();
		}
		/** Netty启动Nio服务端的辅助类 */
		ServerBootstrap bootstrap = new ServerBootstrap();

		bootstrap.group(this.bossGroup, this.workerGroup).option(ChannelOption.SO_BACKLOG, 1024) // 服务端可连接队列数,对应TCP/IP协议listen函数中backlog参数
				.option(ChannelOption.TCP_NODELAY, true)// 立即写出
				.option(ChannelOption.SO_KEEPALIVE, true);// 长连接, 保持连接
		/** Linux平台用Epoll模式 **/
		if (osName.equals("Linux")) { // Linux平台用Epoll模式
			bootstrap.channel(EpollServerSocketChannel.class);
		} else {
			bootstrap.channel(NioServerSocketChannel.class);
		}
		ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.SIMPLE);// 内存泄漏检测 开发推荐PARANOID 线上SIMPLE
		/** 添加解码器、编码器 */

		bootstrap.childHandler(jt808ChannelInitializer);
		/** 绑定端口同步操作 */
		ChannelFuture future = bootstrap.bind(this.port).sync();
		/** 监听端口关闭(//等待客户端链路关闭) **/
		ChannelFuture channelFuture = future.channel().closeFuture().sync();
		if (channelFuture.isSuccess()) {
			log.info("TCP服务启动完毕,port={}", this.port);
		}

	}

	/**
	 * 销毁资源
	 */
	@PreDestroy
	public void destroy() {
		/** 优雅退出,释放资源 */
		// 关闭工作线程组
		this.workerGroup.shutdownGracefully();
		// 关闭主线程组
		this.bossGroup.shutdownGracefully();
		log.info("关闭成功");
	}
}
